// SPDX-License-Identifier: GPL-2.0
/*
 * Copyright (C) Huawei Technologies Co., Ltd. 2023-2023. All rights reserved.
 *
 * Description: Euler Net Boost selftest.
 */
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/bpf.h>
#include <linux/tcp.h>
#include <linux/if_ether.h>

#include <bpf/bpf_endian.h>
#include <bpf/bpf_helpers.h>

#define IP_MF		0x2000
#define IP_OFFSET       0x1FFF

__u16 g_serv_port;
__u32 rcv_msg_len;
__u32 snd_msg_len;
__u16 is_rcv_boost;
__u16 is_snd_boost;

SEC("xdp")
int enboost_ingress_prog(struct xdp_md *ctx)
{
	void *data = (void *)(long)ctx->data;
	void *data_end = (void *)(long)ctx->data_end;
	struct ethhdr *ehdr;
	struct tcphdr *thdr;
	struct iphdr *ihdr;
	__u32 payload_len;

	ehdr = (struct ethhdr *)data;
	if (ehdr + 1 > data_end)
		return XDP_PASS;

	if (ehdr->h_proto != bpf_htons(ETH_P_IP))
		return XDP_PASS;

	ihdr = (struct iphdr *)(ehdr + 1);
	if (ihdr + 1 > data_end)
		return XDP_PASS;

	if (ihdr->ihl != 5 || ihdr->protocol != IPPROTO_TCP)
		return XDP_PASS;

	if (ihdr->frag_off & bpf_htons(IP_MF | IP_OFFSET))
		return XDP_PASS;

	thdr = (struct tcphdr *)(ihdr + 1);
	if (thdr + 1 > data_end)
		return XDP_PASS;

	if (thdr->syn || thdr->fin || thdr->rst)
		return XDP_PASS;

	if (bpf_ntohs(thdr->source) != g_serv_port)
		return XDP_PASS;

	payload_len = bpf_ntohs(ihdr->tot_len) - sizeof(struct iphdr) - thdr->doff * 4;
	if (payload_len == rcv_msg_len)
		is_rcv_boost = 1;

	return XDP_BOOST;
}

SEC("enet/egress")
int enboost_egress_prog(struct __sk_buff *skb)
{
	void *data = (void *)(long)skb->data;
	void *data_end = (void *)(long)skb->data_end;
	struct tcphdr *thdr;
	struct iphdr *ihdr;
	__u32 payload_len;

	if (bpf_ntohl(skb->remote_port) != g_serv_port)
		return ENET_PASS;

	ihdr = (struct iphdr *)data;
	if (ihdr + 1 > data_end)
		return ENET_PASS;

	thdr = (struct tcphdr *)(ihdr + 1);
	if (thdr + 1 > data_end)
		return ENET_PASS;

	if (thdr->syn || thdr->fin || thdr->rst)
		return ENET_PASS;

	payload_len = skb->len - sizeof(struct iphdr) - thdr->doff * 4;
	if (payload_len == snd_msg_len)
		is_snd_boost = 1;

	return ENET_BOOST;
}

char _license[] SEC("license") = "GPL";
